ImageOptim

in a previous post I discussed using ImageOptim to reduce file sizes for websites. I also tried it on some apps. Our apps use lots of images and sounds so they are quite large. The table shows the reduction in size when I used ImageOptim and turned off PNG compression in Xcode. You need to turn off PNG compression because Apple uses their own compression method that is supposed to optimize display time but has a side effect of making file sizes larger. I don’t see any difference in display time, so I’ve opted for smaller file sizes.

 
Title
Original Size (MB) With ImageOptim % Reduction
Show Me…CNS  9.104  7.739 15%
Minimal Pairs 16.723 15.090 10%
Show Me… 38.205 29.682 22%

Disable copy in UIWebView

Great answer from Zubaba at Stackoverflow. I’m using a webView to display colored and bolded text and I had the same problem. I put his solution into a method and call it just after I initialize the webView. I don’t seem to need the delegate.


// This is the end of the method where I initialize the web view
    self.textView = [[UIWebView alloc] initWithFrame:textFrame];
    [self longPress:self.textView];

// This is the method that I added
- (void)longPress:(UIView *)webView {    
    UILongPressGestureRecognizer* longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress)];
    
// Making sure the allowable movement isn't too narrow
    longPress.allowableMovement=100; 
// This is important - the duration must be long enough to allow taps but not longer than the period in which the scroll view opens the magnifying glass
    longPress.minimumPressDuration=0.3;

    longPress.delaysTouchesBegan=YES;
    longPress.delaysTouchesEnded=YES;
    
    longPress.cancelsTouchesInView=YES; // That's when we tell the gesture recognizer to block the gestures we want
    
    [webView addGestureRecognizer:longPress]; // Add the gesture recognizer to the view and scroll view then release
    [webView addGestureRecognizer:longPress];
}

// I just need this for the selector in the gesture recognizer.
- (void)handleLongPress {
        
}

Turning the complier up to 11

I was tracking down a crash caused by memory not being released and I thought it would be helpful to turn on all the compiler options, thinking that maybe it would point to something I did wrong. It didn’t help, but it did generate around a thousand warnings. Only two were actual bugs in the code. Most of the rest were conversion warnings. The most common were defining variables as NSInteger when the method that used them was expecting a CGFloat. Second most common were things like this:


return [[[self fetchedResultsControllerForTableView:tableView] sections] count];

ObjectAtIndex is an unsigned integer so and count is an NSInteger so to get rid of the warning I just cast count to NSUInteger.

return [[[[self fetchedResultsControllerForTableView:tableView] sections] objectAtIndex:(NSUInteger)section] name];

And this


return [[[[self fetchedResultsControllerForTableView:tableView] sections] objectAtIndex:section] numberOfObjects];

which should return an NSInteger rather than an unsigned NSUInteger so here I cast the return value.


 return (NSInteger)[[[[self fetchedResultsControllerForTableView:tableView] sections] objectAtIndex:(NSUInteger)section] numberOfObjects];

Second most common warnings were for unused variables. Since I use the same code for 18 different games I have if statements that determine what the locations of buttons on the screen. Many of the buttons are not used in all of the games so the compiler gives an unused variable warning. To get rid of the warning, I use this line after the last redefinition of the variable. Just so I remember that I’m using it I put it just before I use the “unused” variable. The compiler still compiles correctly when the button is needed, it just doesn’t throw the warning.


  #pragma unused(showHideButtonX)
  #pragma unused(showHideButtonY)
  if ( DISPLAY_SHOWHIDE_BUTTON ) {
      CGRect showHideFrame = CGRectMake(showHideButtonX, showHideButtonY, buttonsSize, buttonsSize);

Checking the logs

We’ve been getting hit with SSH login attempts. Sometimes there were thousands per minute and they slowed the machine to a crawl. So we installed fail2ban and that has slowed the attempts considerably.

Recently one site has been hit with huge numbers of SQL injection attacks (18,000) per day. Right now, I trap them and return a static page.

Here’s what my URL looks like:

/products/product.php?id=1
This is what an attack looks like:


/products/product.php?id=-3000%27%20IN%20BOOLEAN%20MODE%29%20UNION%20ALL%20SELECT%2035%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C%27qopjq%27%7C%7C%27ijiJvkyBhO%27%7C%7C%27qhwnq%27%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35%2C35--%20

I know for sure that this isn’t just a bad link or fat-fingered typing so I don’t want to send them to an overview page. I also don’t want to use any resources on my site delivering static pages.

First I get the productID, then check to see if it is a number. If it is, all is good and I skip the rest of this code. If not, they might have an extra space in the URL from copying and pasting, so I give them the benefit of the doubt and strip them out. If productID is still not a number, I send the page not found response and kill the rest of the page load.


$productID = (isset($_GET['id']) ? mysql_real_escape_string($_GET['id']) : '55');

// Attempts have been made to exploit the database with long strings. 
// This stops it without filling up the error log.
if ( !is_numeric($productID) ) {
    $url = $_SERVER['REQUEST_URI'];
    $ref = $_SERVER['HTTP_REFERER'];
    $ip  = $_SERVER['REMOTE_ADDR'];
    error_log("long string in products.php: URL is $url and IP is $ip & ref is $ref");
    $productID=preg_replace('/[\s]+/','',$productID);
    if ( !is_numeric($productID) ) {
        error_log("Still a long string in products.php after replacement: URL is $url and IP is $ip & ref is $ref");
        header("HTTP/1.0 404 Not Found");
        die();
    }
}

The bot thinks that there isn’t a page there and usually goes away. Sometimes it tries a few more times, but not the thousands of times it used to.