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
// 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.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)
      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:

This is what an attack looks like:


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");
    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");

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.

Things I can’t remember—import SQL file to MySQL

I usually use phpMyAdmin to manipulate tables in my databases but sometimes the file I want to import is too big. In that case I use the command line to import the file.

In this line, I replace a database with formatted sql statements that I’ve edited by hand. the -p flag without an argument will prompt for the root password of the MySQL installation.

mysql -u root -p original_database < /Users/username/Desktop/edited_data.sql

Here I want to replace the entire MySQL database with the backup. I do this on my backup machine from time to time using the nightly My backup. This example shows the password after the flag.

mysql -u root -pYourPassword < mysql-backup.sql